library(tidyverse) # cargamos la librería tidyverse (que incorpora ggplot)
library(ggthemes) # diseños preconfigurados para los gráficos ggplot
library(readxl) # Cargamos readxl para traer levantar excels
Rbase tiene algunos comandos genéricos para realizar gráficos, que se adaptan al tipo de información que se le pide graficar, por ejemplo:
# iris es un set de datos clásico, que ya viene incorporado en R
iris[1:10,]
plot(iris)
#Al especificar una variable, puedo ver el valor que toma cada uno de sus registros (Index)
plot(iris$Sepal.Length,type = "p") # Un punto por cada valor
plot(iris$Sepal.Length,type = "l") # Una linea que una cada valor
plot(iris$Sepal.Length,type = "b") #Ambas
hist(iris$Sepal.Length, col = "lightsalmon1", main = "Histograma")
La función png() nos permite grabar una imagen en el disco. Lleva como argumento principal la ruta completa a donde se desea guardar la misma, incluyendo el nombre que queremos dar al archivo. A su vez pueden especificarse otros argumentos como el ancho y largo de la imagen, entre otros.
ruta_archivo <- "../grafico1.PNG"
ruta_archivo
png(ruta_archivo)
plot(iris$Sepal.Length,type = "b")
dev.off()
La función png() abre el dispositivo de imagen en el directorio especificado. Luego creamos el gráfico que deseamos (o llamamos a uno previamente construido), el cual se desplegará en la ventana inferior derecha de la pantalla de Rstudio. Finalmente con dev.off() se cierra el dispositivo y se graban los gráficos.
Los gráficos del R base son útiles para escribir de forma rápida y obtener alguna información mientras trabajamos. Muchos paquetes estadísticos permiten mostrar los resultados de forma gráfica con el comando plot (por ejemplo, las regresiones lineales lm()).
Sin embargo, existen librerías mucho mejores para crear gráficos de nivel de publicación. La más importante es ggplot2, que a su vez tiene extensiones mediante otras librerías.
ggplot tiene su sintaxis propia. La idea central es pensar los gráficos como una sucesión de capas, que se construyen una a la vez.
El operador + nos permite incorporar nuevas capas al gráfico.
El comando ggplot() nos permite definir la fuente de datos y las variables que determinaran los ejes del grafico (x,y), así como el color y la forma de las líneas o puntos,etc.
Las sucesivas capas nos permiten definir:
geom_col(), de línea, geom_line(), de puntos, geom_point(), boxplot, geom_boxplot())labs()theme()scale_y_continuous,scale_x_discretefacet_wrap(),facet_grid()ggplot tiene muchos comandos, y no tiene sentido saberlos de memoria, es siempre útil reutilizar gráficos viejos y tener a mano el machete.
Esta forma de pensar los gráficos nos permite repenser los distintos atributos como potenciales aliados a la hora de mostrar información multidimensional. Por ejemplo:
color color =
rellenofill =
forma shape =
tamaño size =
transparencia alpha =
Abrir un mismo gráfico según alguna variable discreta: facet_wrap()
Los atributos que queremos que mapeen una variable, deben ir dentro del aes(), aes(... color = variable)
Cuando queremos simplemente mejorar el diseño (es fijo), se asigna por fuera, o dentro de cada tipo de gráficos, geom_col(color = 'green').
A continuación vamos a crear un dataframe como insumo para realizar un gráfico de puntos. Visualizaremos el salario promedio y la tasa de no registro, para cada uno de los aglomerados EPH. El tamaño de los puntos estará seteado en función de la cantidad de asalariados, y el color en función de la región de pertenencia
Individual_t119 <- read.table("../Fuentes/usu_individual_t119.txt",
sep=";", dec=",", header = TRUE, fill = TRUE)
aglomerados <- read_excel("../Fuentes/Aglomerados EPH.xlsx")
regiones <- read_excel("../Fuentes/Regiones.xlsx")
salario_y_no_registro <- Individual_t119 %>%
filter(ESTADO == 1, CAT_OCUP == 3) %>%
group_by(ANO4,TRIMESTRE,REGION,AGLOMERADO) %>%
summarise(tasa_no_reg = sum(PONDERA[PP07H == 2])/sum(PONDERA),
salario_prom = weighted.mean(P21,PONDIIO),
asalariados = sum(PONDERA)) %>%
ungroup() %>%
left_join(aglomerados,by = c("AGLOMERADO")) %>%
left_join(regiones,by = c("REGION"))
salario_y_no_registro
Capas del Gráfico
Veamos ahora, el “paso a paso” o “capa a capa” del gráfico. Dentro de ggplot():
data =aes()capa1 <- ggplot(data = salario_y_no_registro,
aes(x = salario_prom,
y = tasa_no_reg,
size = asalariados,
color = Region))
capa1
capa2 <- capa1 +
geom_point()
capa2
capa3 <- capa2 +
labs(title = "Salario promedio y tasa de no registro por aglomerados",
subtitle = "31 Aglomerados. 1er Trimestre de 2019.",
x = "Salario promedio",
y = "Tasa de no registro")
capa3
theme() puedo cambiar el diseño del cuadrante donde se visualizan los datos. En este caso usé la función theme_minimal()del paquete ggthemes que tiene definido un tema con fondo blanco y pequeñas líneas grises para seguir la línea de los números que se muestran en el eje.guides() es donde puedo modificar todo lo vinculado a las leyendas del gráfico. En este caso, lo usamos para eliminar la leyenda asociada al tamaño de los puntos. También allí podría modificar el título de la otra leyenda, el tamaño de los puntos, etc.scale_y_continuous() y scale_x_continuous() me permiten modificar las escalas de los respectivos ejes, cambiar el formato en el que aparecen los números, o cuántas referencias mostrar de la escala en cuestión.grafico_final <- capa3 +
theme_minimal()+
guides(size = FALSE)+
scale_y_continuous(labels = scales::percent_format(accuracy = 1))+
scale_x_continuous(labels = scales::number_format(big.mark = ".",decimal.mark = ","))
grafico_final
La librería GGplot tiene a su vez muchas otras librerías que extienden sus potencialidades. Entre nuestras favoritas están:
Con la librería plotly podemos rápidamente hacer interactivo un gráfico de ggplot. Simplemente tenemos que aplicar al función ggplotly() a nuestro gráfico.
En el parámetro tooltip = le podemos pasar que variable queremos que se muestre al pasar por la geometría del gráfico con el mouse.
library(plotly)
grafico_final <- ggplot(data = salario_y_no_registro,
aes(x = salario_prom,
y = tasa_no_reg,
size = asalariados,
aglo = Nom_Aglo, #Aca creo un parametro del aes que depende de Nom_Aglo
color = Region))+
geom_point()+
labs(title = "Salario promedio y tasa de no registro por aglomerados",
subtitle = "31 Aglomerados. 1er Trimestre de 2019.",
x = "Salario promedio",
y = "Tasa de no registro")+
theme_minimal()+
guides(size = F)+
scale_y_continuous(labels = scales::percent_format(accuracy = 1))+
scale_x_continuous(labels = scales::number_format(big.mark = ".",decimal.mark = ","))
ggplotly(grafico_final,tooltip = "aglo")
Permite visualizar rápidamente el cruce de todas las variables de un dataframe
library(GGally)
ggpairs(iris, mapping = aes(color = Species))
base_para_otros_ejemplos <- Individual_t119 %>%
left_join(regiones) %>%
filter(P21>0) %>%
mutate(Sexo = case_when(CH04 == 1 ~ "Varón",
CH04 == 2 ~ "Mujer"))
Util para comparar distribuciones según distintas categorías
library(ggridges)
ggplot(base_para_otros_ejemplos, aes(x = P21, y = Sexo, fill=Sexo)) +
geom_density_ridges()+
scale_x_continuous(limits = c(0,60000))#Restrinjo el gráfico hasta ingresos de $60000
También hay extensiones que te ayudan a escribir el código, como esquisse
iris <- iris
#Correr en la consola
esquisse::esquisser()
ggplot(base_para_otros_ejemplos, aes(x = Region, y = P21)) +
geom_boxplot()+
scale_y_continuous(limits = c(0, 40000))#Restrinjo el gráfico hasta ingresos de $40000
Si queremos agregar la dimensión sexo, podemos hacer un facet_wrap()
ggplot(base_para_otros_ejemplos, aes(x= Region, y = P21 ,fill = Region )) +
geom_boxplot()+
scale_y_continuous(limits = c(0, 40000))+
facet_wrap(vars(Sexo))
Por la forma en que está presentado el gráfico, el foco de atención sigue puesto en las diferencias de ingresos entre regiones. Simplemente se agrega un corte por la variable de sexo.
Si lo que queremos hacer es poner el foco de atención en las diferencias por sexo, simplemente basta con invertir la variable x especificada con la variable utilizada en el facet_wrap
ggplot(base_para_otros_ejemplos, aes(x= Sexo, y = P21, group = Sexo, fill = Sexo )) +
geom_boxplot()+
scale_y_continuous(limits = c(0, 40000))+
facet_wrap(vars(Region),nrow = 1) +
theme(legend.position = "none")
Por ejemplo, si observamos el ingreso de la ocupación principal:
ggplot(base_para_otros_ejemplos, aes(x = P21,weights = PONDIIO))+
geom_histogram(fill='salmon', color='grey25')+
scale_x_continuous(limits = c(0,50000))
En este gráfico, los posibles valores de p21 se dividen en 30 bins consecutivos y el gráfico muestra cuantas observaciones caen en cada uno de ellos
La función geom_density() nos permite construir kernels de la distribución. Es particularmente útil cuando tenemos una variable continua, dado que los histogramas rompen esa sensación de continuidad.
Veamos un ejemplo sencillo con los ingresos de la ocupación principal. Luego iremos complejizandolo
ggplot(base_para_otros_ejemplos, aes(x = P21,weights = PONDIIO))+
geom_density(fill='salmon', color='grey25')+
scale_x_continuous(limits = c(0,50000))
El eje y no tiene demasiada interpretabilidad en los Kernel, porque hace a la forma en que se construyen las distribuciones.
El parametro adjust, dentro de la función geom_densitynos permite reducir o ampliar el rango de suavizado de la distribución. Su valor por default es 1. Veamos que sucede si lo seteamos en 2
ggplot(base_para_otros_ejemplos, aes(x = P21,weights = PONDIIO))+
geom_density(adjust = 2,fill='salmon', color='grey25')+
scale_x_continuous(limits = c(0,50000))
Como es esperable, la distribución del ingreso tiene “picos” en los valores redondos, ya que la gente suele declarar un valor aproximado al ingreso efectivo que percibe. Nadie declara ingresos de 30001. Al suavizar la serie con un kernel, eliminamos ese efecto.Si seteamos el rango para el suavizado en valores menores a 1, podemos observar estos picos.
ggplot(base_para_otros_ejemplos, aes(x = P21,weights = PONDIIO))+
geom_density(adjust = 0.01,fill='salmon', color='grey25')+
scale_x_continuous(limits = c(0,50000))
Para realizar estos gráficos, vamos a modificar un poco los datos:
levels(). El “\n”" es un caracter especial que permite que el string continúe en la siguiente línea.ggdata <- base_para_otros_ejemplos %>%
filter(!is.na(NIVEL_ED),
NIVEL_ED!=7,
PP04A !=3) %>%
mutate(NIVEL_ED = factor(case_when(NIVEL_ED == 1 ~ 'Primaria \n Incompleta', # '\n' significa carriage return, o enter
NIVEL_ED == 2 ~ 'Primaria \n Completa',
NIVEL_ED == 3 ~ 'Secundaria \nIncompleta',
NIVEL_ED == 4 ~ 'Secundaria \nCompleta',
NIVEL_ED == 5 ~ 'Superior \nUniversitaria \nIncompleta',
NIVEL_ED == 6 ~ 'Superior \nUniversitaria \nCompleta',
FALSE ~ 'Otro'),
levels= c('Primaria \n Incompleta',
'Primaria \n Completa',
'Secundaria \nIncompleta',
'Secundaria \nCompleta',
'Superior \nUniversitaria \nIncompleta',
'Superior \nUniversitaria \nCompleta')),
Sexo = case_when(CH04 == 1 ~ 'Varón',
CH04 == 2 ~ 'Mujer'),
Establecimiento = case_when(PP04A == 1 ~ 'Estatal',
PP04A == 2 ~ 'Privado',
FALSE ~ 'Otro'))
ggdata
Para graficar un suavizado de las series, se utiliza la función geom_smooth(). Con suavizado nos referimos al gráfico de un modelo realizado sobre los datos, que estima el valor en el punto x,y (para el grupo). Las regresiones lineales son un ejemplo de esto, aunque no el único, ni el que viene por default.
ggplot(ggdata, aes(CH06, P21, colour = Sexo, shape = Sexo, alpha = P21))+
geom_smooth() +
labs(
x = 'Edad',
y = 'ingreso',
title = 'Ingreso por ocupación principal',
subtitle = 'Según edad, nivel educativo y sexo') +
theme_minimal()+
scale_y_continuous()+
scale_alpha(guide = FALSE)+
facet_grid(~NIVEL_ED)
Si corremos el comando geom_smooth() por default, nos advierte que esta utilizando el método GAM, de general additive models.
el sombreado gris que envuelve cada línea es el intervalo de confianza de dicho punto (95% por default).
También podemos utilizar métodos lineales, agregando el parámetro method = 'lm'. Haciendo esto, el gráfico muestra una regresión lineal simple. Si queremos otro tipo de regresión lineal, le podemos explicitar la fórmula.
En el ejemplo siguiente, utilizamos la formula \(y = \beta_0 +\beta_1x +\beta_2 x^2\).
ggplot(ggdata, aes(CH06, P21, colour = Sexo, weight = PONDIIO)) +
geom_smooth(method = "lm", formula = y ~ poly(x, 2)) +
labs(x = 'Edad',
y = 'ingreso',
title = 'Regresion cuadrática del Ingreso por ocupación principal respecto de la Edad',
subtitle = 'Según Nivel educativo y sexo') +
theme_minimal()+
facet_grid( ~ NIVEL_ED)
Si quisiéramos, además de ver la relación entre ingreso, Edad, Sexo y Nivel educativo, incorporar el tipo de establecimiento,público o privado. Podemos facetear el gráfico por dos variables en lugar de una, lo que crea una matriz de gráficos según los cruces.
ggplot(ggdata, aes(CH06, P21, colour = Establecimiento, weight = PONDIIO)) +
geom_smooth(method = "lm") +
labs(
x = 'Edad',
y = 'ingreso',
title = 'Tendencia del ingreso por ocupación principal',
subtitle = 'Según edad, nivel educativo, sexo y tipo de establecimiento') +
theme_minimal()+
facet_grid(Sexo ~ NIVEL_ED)
#ggsave(filename = paste0("../regresion lineal.png"),scale = 2)